
export type EaseInOutOption = {
  autoplay?: boolean
  startVal: number
  endVal: number
  duration?: number
  useEasing?: boolean
  isFormat?: boolean
  decimals?: number
  decimal?: string
  separator?: string
  prefix?: string
  suffix?: string
  running?: (value: any) => void
  finished?: (value: any) => void
}

/**
 * 匀加速递增
 */
class EaseInOut {
  autoplay = false
  startVal = 0
  endVal = 0
  displayValue = 0
  printVal = 0
  duration = 3000
  startTime = 0
  rAF = 0
  useEasing = true
  isFormat = false
  decimals = 0
  decimal = '.'
  /** 千分位符号*/
  separator = ''
  prefix = ''
  suffix = ''
  easingFn = (t: number, b: number, c: number, d: number) => {
    return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
  }
  running = (value: any) => { }
  finished = (value: any) => { }

  constructor(data?: EaseInOutOption) {

    data && this.init(data)
  }

  init(data: EaseInOutOption) {
    data.startVal && (this.startVal = data.startVal)
    data.endVal && (this.endVal = data.endVal)
    data.duration && (this.duration = data.duration)
    data.useEasing && (this.useEasing = data.useEasing)
    data.isFormat && (this.isFormat = data.isFormat)
    data.decimals && (this.decimals = data.decimals)
    data.decimal && (this.decimal = data.decimal)
    data.separator && (this.separator = data.separator)
    data.prefix && (this.prefix = data.prefix)
    data.suffix && (this.suffix = data.suffix)
    data.running && (this.running = data.running)
    data.finished && (this.finished = data.finished)
    data.autoplay && (this.autoplay = data.autoplay) && this.start()
  }

  getRAF() {
    return this.rAF
  }

  start() {

    this.rAF = requestAnimationFrame((timestamp) => this.count(timestamp))
  }

  stop() {
    cancelAnimationFrame(this.rAF)
  }

  count(timestamp: number) {
    if (!this.startTime) this.startTime = timestamp;

    const progress = timestamp - this.startTime;

    if (this.useEasing) {
      if (this.startVal > this.endVal) {
        this.printVal = this.startVal - this.easingFn(progress, 0, this.startVal - this.endVal, this.duration)
      } else {
        this.printVal = this.easingFn(progress, this.startVal, this.endVal - this.startVal, this.duration);
      }
    } else {
      if (this.startVal > this.endVal) {
        this.printVal = this.startVal - ((this.startVal - this.endVal) * (progress / this.duration));
      } else {
        this.printVal = this.startVal + (this.endVal - this.startVal) * (progress / this.duration);
      }
    }
    if (this.startVal > this.endVal) {
      this.printVal = this.printVal < this.endVal ? this.endVal : this.printVal;
    } else {
      this.printVal = this.printVal > this.endVal ? this.endVal : this.printVal;
    }

    const displayValue = this.formatNumber(this.printVal)

    const runningCb = this.running(displayValue)

    if (runningCb !== undefined) {
      this.stop()
      return
    }
    if (progress < this.duration) {
      this.rAF = requestAnimationFrame((timestamp) => this.count(timestamp));
    } else {
      this.finished(displayValue)
      this.stop()
    }
  }

  isNumber(val: any) {
    return !isNaN(parseFloat(val))
  }

  formatNumber(num: any) {
    num = num.toFixed(this.decimals);
    if (!this.isFormat) return num
    num += '';
    const x = num.split('.');
    let x1 = x[0];
    const x2 = x.length > 1 ? this.decimal + x[1] : '';
    const rgx = /(\d+)(\d{3})/;
    if (this.separator && !this.isNumber(this.separator)) {
      while (rgx.test(x1)) {
        x1 = x1.replace(rgx, '$1' + this.separator + '$2');
      }
    }
    return this.prefix + x1 + x2 + this.suffix;
  }
}

export default EaseInOut